package com.leyou.search;

import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.client.BrandClient;
import com.leyou.client.CategoryClient;
import com.leyou.client.GoodsClient;
import com.leyou.client.SpecificationClient;
import com.leyou.common.utils.JsonUtils;
import com.leyou.common.vo.PageResult;
import com.leyou.pojo.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SearchService {

    @Autowired
    private CategoryClient categoryClient;

    @Autowired
    private GoodsClient goodsClient;

    @Autowired
    private SpecificationClient specificationClient;

    @Autowired
    private BrandClient brandClient;

    @Autowired
    private GoodsRepository repository;

    @Autowired
    private ElasticsearchTemplate template;
    public Goods buildGoods(Spu spu){
        //查找分类
        List<Category> categories = categoryClient.queryNameByIds(Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()));
        List<String> names = categories.stream().map(Category::getName).collect(Collectors.toList());
        String all = spu.getTitle()+ StringUtils.join(names," ");
        //查找品牌
        Brand brand = brandClient.queryBrandById(spu.getBrandId());
        //查找sku
        List<Sku> skus = goodsClient.querySkuBySpuId(spu.getId());
        List<Map<String,Object>> list = new ArrayList<>();
        for (Sku sku : skus) {
            Map<String,Object> map = new HashMap<>();
            map.put("id",sku.getId());
            map.put("title",sku.getTitle());
            map.put("price",sku.getPrice());
            map.put("image",StringUtils.substringBefore(sku.getImages(),","));
            list.add(map);
        }
        Set<Long> prices = skus.stream().map(Sku::getPrice).collect(Collectors.toSet());

        //查询规格参数
        List<SpecParam> specParams = specificationClient.queryParamByid(spu.getCid3(), true);
        SpuDetail spuDetail = goodsClient.querySpuDetailById(spu.getId());
        Map<Long, String> gens = JsonUtils.parseMap(spuDetail.getGenericSpec(), Long.class, String.class);
        Map<Long, List<String>> spec = JsonUtils.nativeRead(spuDetail.getSpecialSpec(), new TypeReference<Map<Long, List<String>>>() {});
        Map<String,Object> map = new HashMap<>();
        for (SpecParam specParam : specParams) {
            String key = specParam.getName();
            Object val;
            if(specParam.getGeneric()){
                val = gens.get(specParam.getId());
                if(specParam.getNumeric().equals("1")){
                    val = chooseSegment(val.toString(),specParam);
                }
            }else{
                val = spec.get(specParam.getId());
            }
            map.put(key,val);
        }

        Goods goods = new Goods();
        goods.setBrandId(spu.getBrandId());
        goods.setCid1(spu.getCid1());
        goods.setCid2(spu.getCid2());
        goods.setCid3(spu.getCid3());
        goods.setCreateTime(spu.getCreateTime());
        goods.setId(spu.getId());
        goods.setAll(all);
        goods.setPrice(prices);
        goods.setSkus(JsonUtils.serialize(list));
        goods.setSpecs(map);
        goods.setSubTitle(spu.getSubTitle());
        return  goods;
    }

    private String chooseSegment(String value, SpecParam p) {
        double val = NumberUtils.toDouble(value);
        String result = "其它";
        // 保存数值段
        for (String segment : p.getSegments().split(",")) {
            String[] segs = segment.split("-");
            // 获取数值范围
            double begin = NumberUtils.toDouble(segs[0]);
            double end = Double.MAX_VALUE;
            if(segs.length == 2){
                end = NumberUtils.toDouble(segs[1]);
            }
            // 判断是否在范围内
            if(val >= begin && val < end){
                if(segs.length == 1){
                    result = segs[0] + p.getUnit() + "以上";
                }else if(begin == 0){
                    result = segs[1] + p.getUnit() + "以下";
                }else{
                    result = segment + p.getUnit();
                }
                break;
            }
        }
        return result;
    }

    public PageResult<Goods> search(SearchRequest request) {
        int page = request.getPage()-1;
        int size = request.getSize();
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        //结果过滤
        builder.withSourceFilter(new FetchSourceFilter(new String[]{"id","subTitle","skus"},null));
        //分页
        builder.withPageable(PageRequest.of(page,size));
        //过滤
        if(!StringUtils.isBlank(request.getKey())){
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            //查询条件
            boolQueryBuilder.must(QueryBuilders.matchQuery("all",request.getKey()));
            Map<String, String> map = request.getFilter();
            if(map!=null){
                for (Map.Entry<String, String> ent : map.entrySet()) {
                    String key = ent.getKey();
                    String val = ent.getValue();
                    if(key!="brandId" && key!="cid3"){
                        key = "specs."+key+".keyword";
                    }
                    boolQueryBuilder.filter(QueryBuilders.termQuery(key,val));
                }
            }
            builder.withQuery(boolQueryBuilder);
        }

        //聚合
        TermsAggregationBuilder brand = AggregationBuilders.terms("brand").field("brandId");
        TermsAggregationBuilder category = AggregationBuilders.terms("category").field("cid3");
        builder.addAggregation(brand);
        builder.addAggregation(category);
        AggregatedPage<Goods> result = template.queryForPage(builder.build(), Goods.class);
        Aggregations aggregations = result.getAggregations();
        LongTerms brandTerms =  (LongTerms)aggregations.asMap().get("brand");
        List<LongTerms.Bucket> brandBuckets = brandTerms.getBuckets();
        List<Long> ids = brandBuckets.stream().map(b->b.getKeyAsNumber().longValue()).collect(Collectors.toList());
        List<Brand> brands = brandClient.queryList(ids);

        LongTerms categoryTerms =  (LongTerms)aggregations.asMap().get("category");
        List<Long> cids = categoryTerms.getBuckets().stream().map(b -> b.getKeyAsNumber().longValue()).collect(Collectors.toList());
        List<Category> categories = categoryClient.queryNameByIds(cids);
        List<Map<String, Object>> spec = null;
        if(categories!=null && categories.size()==1){
            spec = buildSpec(categories.get(0).getId(), request);
        }
        //解析结果
        long total = result.getTotalElements();
        long totalpage = result.getTotalPages();
        List<Goods> list = result.getContent();
        return new SearchResult(total,totalpage,list,brands,categories,spec);
    }

    private List<Map<String,Object>> buildSpec(Long id,SearchRequest request) {
        List<Map<String,Object>> list = new ArrayList<>();
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        if(!StringUtils.isBlank(request.getKey())){
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            //查询条件
            boolQueryBuilder.must(QueryBuilders.matchQuery("all",request.getKey()));
            Map<String, String> map = request.getFilter();
            if(map!=null){
                for (Map.Entry<String, String> ent : map.entrySet()) {
                    String key = ent.getKey();
                    String val = ent.getValue();
                    if(key!="brandId" && key!="cid3"){
                        key = "specs."+key+".keyword";
                    }
                    boolQueryBuilder.filter(QueryBuilders.termQuery(key,val));
                }
            }
            builder.withQuery(boolQueryBuilder);
        }
        List<SpecParam> specParams = specificationClient.queryParamByid(id, true);
        for (SpecParam specParam : specParams) {
            String name = specParam.getName();
            builder.addAggregation(AggregationBuilders.terms(name).field("specs." + specParam.getName() + ".keyword"));
        }
        AggregatedPage<Goods> result = template.queryForPage(builder.build(), Goods.class);
        Aggregations aggregations = result.getAggregations();
        for (SpecParam specParam : specParams) {
            String name = specParam.getName();
            StringTerms terms = (StringTerms)aggregations.asMap().get(name);
            List<String> collect = terms.getBuckets().stream().map(b -> b.getKeyAsString()).collect(Collectors.toList());
            //map
            Map map = new HashMap();
            map.put("k",name);
            map.put("value",collect);
            list.add(map);
        }
        return  list;
    }
}
